#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <cmath>
#ifdef WIN32
#include <GL/glew.h>
#include <GL/glut.h>
#else
#include <GL/glew.h>
#include <GL/glut.h>
#endif
#include "draw.h"
#include "shader.h"

/*	Create checkerboard texture	*/
#define	checkImageWidth 64
#define	checkImageHeight 64
static GLubyte checkImage[checkImageHeight][checkImageWidth][4];

#ifdef GL_VERSION_1_1
static GLuint texName;
#endif
//extern GLuint v,f,f2,p;
float lpos[4] = {1,0.5,1,0};
Shader shader; 





void makeCheckImage(void)
{
	int i, j, c;
    
	for (i = 0; i < checkImageHeight; i++) {
		for (j = 0; j < checkImageWidth; j++) {
			c = ((((i&0x8)==0)^((j&0x8))==0))*255;
			checkImage[i][j][0] = (GLubyte) c;
			checkImage[i][j][1] = (GLubyte) c;
			checkImage[i][j][2] = (GLubyte) c;
			checkImage[i][j][3] = (GLubyte) 255;
		}
	}
}

void init(void)
{    
	glClearColor (0.0, 0.0, 0.0, 0.0);
	glShadeModel(GL_FLAT);
	glEnable(GL_DEPTH_TEST);

	makeCheckImage();
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

#ifdef GL_VERSION_1_1
	glGenTextures(1, &texName);
	glBindTexture(GL_TEXTURE_2D, texName);
#endif

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
#ifdef GL_VERSION_1_1
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, checkImageWidth, checkImageHeight, 
				 0, GL_RGBA, GL_UNSIGNED_BYTE, checkImage);
#else
	glTexImage2D(GL_TEXTURE_2D, 0, 4, checkImageWidth, checkImageHeight, 
				 0, GL_RGBA, GL_UNSIGNED_BYTE, checkImage);
#endif

}
void draw_triangles (Point point[3], GLfloat color [40], int res, GLfloat k, GLfloat h, GLfloat c)
{		

	std::cout<<"Value k "<<k<<std::endl;
	std::cout<<"Value h "<<h<<std::endl;
	std::cout<<"Value c "<<c<<std::endl;

	shader.set_uniform("res", res);
	shader.set_uniform("color", color, 10);
	shader.set_uniform("k", k); 
	shader.set_uniform("h", h);
	shader.set_uniform("c", c);

	glBegin(GL_TRIANGLES);
	glTexCoord2f(0.0, 0.0); glVertex3f(point[0].x, point[0].y, point[0].z);
	glTexCoord2f(c, 0.0); glVertex3f(point[1].x, point[1].y, point[1].z);
	glTexCoord2f(k, h); glVertex3f(point[2].x, point[2].y, point[2].z);
	glEnd();
	glFlush();
}
GLfloat comput_k(Point p[3])
{
	float a = (p[1]-p[2]).length(); 
	float b = (p[2]-p[0]).length();
	float c = (p[0]-p[1]).length();
	float k = (b*b + c * c - a * a) / (2.0 * c) ; 
	std::cout<<"a "<<a<<" b "<<b<<" c "<<c<<" k "<<k<<std::endl;
	return GLfloat (k); 
}
GLfloat compute_h(Point p[3])
{
	float a = (p[1]-p[2]).length(); 
	float b = (p[2]-p[0]).length();
	float c = (p[0]-p[1]).length();
	float cos_a = (b*b + c* c - a* a)/ (2.0 * b * c) ;
	float sin_a = sqrt (1.0 - cos_a * cos_a) ;
	return (b * sin_a) ;
}
GLfloat compute_c(Point p[3])
{
	return (p[0] - p[1]).length();
}
void display(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	glEnable(GL_TEXTURE_2D);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
#ifdef GL_VERSION_1_1
	glBindTexture(GL_TEXTURE_2D, texName);
#endif
	

	GLint uniformLoc_color = 0;
	GLint uniform_vertex_pos =0;
	GLint uniform_res=0;

	uniformLoc_color = shader.get_uniform("color");
	uniform_vertex_pos = shader.get_uniform("k");
	uniform_res = shader.get_uniform ("res");
	

	GLfloat color1 [40] ={1.0,0.0,0.0,1.0,  //red
						  0.0,1.0,0.0,1.0,  //green
						  0.0,0.0,1.0,1.0,  //blue
						  1.0,1.0,0.0,1.0,
						  0.0,1.0,1.0,1.0,
						  1.0,0.0,1.0,1.0,
						  1.0,0.5,1.0,1.0,
						  0.5,1.0,1.0,1.0,
						  1.0,1.0,0.5,1.0,
						  1.0,1.0,1.0,1.0};
	Point point[3];
	//point[0].x = -1.0; point[0].y = -1.0; point[0].z = 0.0 ; 
	//point[1].x = 1.0; point[1].y = -1.0; point[1].z = 0.0 ;
	//point[2].x = 0.0; point[2].y = 1.0; point[2].z = 0.0 ; 

	point[2].x = -1.0; point[2].y = -1.0; point[2].z = 0.0 ; 
	point[1].x = 1.0; point[1].y = -1.0; point[1].z = 0.0 ;
	point[0].x = 0.0; point[0].y = 1.0; point[0].z = 0.0 ; 

	
	float k = comput_k(point);
	float h = compute_h(point);
	float c = compute_c(point);

	if (h >=c)
	{
		draw_triangles(point, color1, 2, k / h, 1.0, c /h );
	}
	else
	{
		draw_triangles(point, color1, 2, k / c, h / c, 1.0 );
	}

	/*
	GLfloat color2 [40] ={0.0,1.0,0.0,1.0,
						  0.0,0.0,1.0,1.0,
						  1.0,0.0,0.0,1.0,
						  1.0,1.0,0.5,1.0,
						  1.0,1.0,1.0,1.0,
						  1.0,0.5,1.0,1.0,
						  1.0,0.5,0.0,1.0,
						  0.5,0.0,1.0,1.0,
						  1.0,0.0,0.5,1.0,
						  1.0,0.5,0.5,1.0};
	shader.set_uniform("color", color2, 10);
	shader.set_uniform("k", 0.0f); 
	shader.set_uniform("res", 2);
	point[0].x = 1.0; point[0].y = -1.0; point[0].z = 0.0 ; 
	point[1].x = 2.0; point[1].y = -1.0; point[1].z = 0.0 ;
	point[2].x = 1.0; point[2].y = .5; point[2].z = 0.0 ;
	draw_triangles(point, color2, 0.0f);
	*/

	glFlush();
	glDisable(GL_TEXTURE_2D);

}

void reshape(int w, int h)
{
	glViewport(0, 0, (GLsizei) w, (GLsizei) h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 30.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glTranslatef(0.0, 0.0, -3.6);
}

void keyboard (unsigned char key, int x, int y)
{
	switch (key) {
	case 27:
		exit(0);
		break;
	default:
		break;
	}
}

int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(800, 450);
	glutInitWindowPosition(100, 100);
	glutCreateWindow(argv[0]);
	init();
	int major;
	int minor;
	getGLVersion(& major, & minor);
	std::cout<<major<<' '<<minor<<std::endl;

	getGLSLVerstion(&major, & minor);
	std::cout<<major<<' '<<minor<<std::endl;

	glewInit();
	if (glewIsSupported("GL_VERSION_2_0"))
		printf("Ready for OpenGL 2.0\n");
	else {
		printf("OpenGL 2.0 not supported\n");
		exit(1);
	}

#ifdef WIN32
	shader.load("D:\\workspace\\shader\\glsl\\minimal.vert", "D:\\workspace\\shader\\glsl\\mcolor.frag");
#else
	shader.load("glsl/minimal.vert", "glsl/minimal.frag");
#endif
	shader.bind();

	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutKeyboardFunc(keyboard);



	
/*
  GLint uniformLoc ;
  uniformLoc = glGetUniformLocation(p, "resolution");
  if (uniformLoc != -1)
  {
  glUniform1i(uniformLoc, 1);
  }
  else
  {
  printf ("ERROR");
  exit(0);
  }

*/

	glutMainLoop();
	return 0; 
}
